﻿/*
 *	Copyright (c) 2009 Queensland University of Technology. All rights reserved.
 *	The QUT Bioinformatics Collection is open source software released under the 
 *	Microsoft Public License (Ms-PL): http://www.microsoft.com/opensource/licenses.mspx.
 */
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Xml.Linq;
using System.Text;
using QUT.Bio.SilverMap.ObjectModel;
using QUT.Bio.Util;

namespace BlastExplorer.SilverMapDataProducer {
	/// <summary>
	/// Provides a SilverMap object model that encapsulates a collection of blast results.
	/// </summary>

	public class ObjectModel : IFeatureCollection {
		public readonly List<String> RequestIds = new List<String>();

		public readonly Dictionary<SequenceKey, ILinearDomain> sequences = new Dictionary<SequenceKey, ILinearDomain>();
		internal readonly HashList<IFeature> features = new HashList<IFeature>();
		internal readonly SparseMatrix<IFeature, IFeature, QUT.Bio.SilverMap.ObjectModel.Hit> hits = new SparseMatrix<IFeature, IFeature, QUT.Bio.SilverMap.ObjectModel.Hit>();
		internal ILinearDomain initialQuerySequence;
		internal readonly HashList<ILinearDomain> querySequences = new HashList<ILinearDomain>();

		public IEnumerable<ILinearDomain> Domains {
			get {
				return sequences.Values;
			}
		}

		public IEnumerable<IFeature> Features {
			get {
				return features;
			}
		}

		public IEnumerable<QUT.Bio.SilverMap.ObjectModel.Hit> Hits {
			get {
				return from triple in hits
					   select triple.Third;
			}
		}

		public ILinearDomain InitialFocus {
			get {
				return initialQuerySequence;
			}
			set {
				initialQuerySequence = value;
			}
		}

		public XElement Xml {
			get {
				XElement collectionElement = new XElement( "Collection" );
				XElement requestIdElement = new XElement( "RequestIds" );
				XElement sequenceElement = new XElement( "Sequences" );
				XElement hitElement = new XElement( "Hits" );
				XElement initialQuerySequence = new XElement( "InitialQuerySequence",
					this.initialQuerySequence == null ? "null" : ( (Sequence) this.initialQuerySequence ).Id
				);

				collectionElement.Add( sequenceElement, hitElement, initialQuerySequence, requestIdElement );

				foreach ( ILinearDomain iSeq in sequences.Values ) {
					Sequence seq = (Sequence) iSeq;
					sequenceElement.Add( seq.ToXml() );
				}

				foreach ( Hit hit in Hits ) {
					hitElement.Add( hit.ToXml() );
				}

				foreach ( string requestId in RequestIds ) {
					requestIdElement.Add( new XElement( "Id", requestId ) );
				}

				return collectionElement;
			}
			set {
				foreach ( XElement sequenceElement in value.Element( "Sequences" ).Nodes() ) {
					Sequence seq = Sequence.FromXml( sequenceElement );

					if ( !sequences.ContainsKey( seq.Key ) ) {
						sequences.Add( seq.Key, seq );
					}
				}

				foreach ( XElement hitElement in value.Element( "Hits" ).Nodes() ) {
					try {
						Hit hit = Hit.FromXml( hitElement, this );
						hits[hit.QueryFeature, hit.HitFeature] = hit;
						querySequences.Add( hit.QueryFeature.ContainingSequence );
					}
					catch ( Exception e ) {
						// BUG: Sequences are not being added where the Regex pattern doesn't match.
						// TODO: is this still an issue???
						Debug.WriteLine( String.Format( "Exception: {0}", e ) );
					}
				}

				try {
					XElement element = value.Element( "InitialQuerySequence" );
					SequenceKey key = new SequenceKey(
						(SequenceSource) Enum.Parse( typeof( SequenceSource ), element.Attribute( "Source" ).Value ),
						element.Attribute( "Id" ).Value
					 );
					initialQuerySequence = sequences[key];
				}
				catch {
					try {
						string initialQuerySequenceId = value.Element( "InitialQuerySequence" ).Value;
						SequenceKey key = new SequenceKey( SequenceSource.Genbank, initialQuerySequenceId );
						initialQuerySequence = initialQuerySequenceId == "null" ? null : sequences[key];
					}
					catch {
						initialQuerySequence = null;
					}
				}

				try {
					foreach ( XElement IdElement in value.Element( "RequestIds" ).Nodes() ) {
						RequestIds.Add( IdElement.Value );
					}
				}
				catch {
				}
			}
		}

		public HashList<ILinearDomain> Focii {
			get {
				return querySequences;
			}
		}
	}
}
